package com.haiyou.data.sdk.account.token;

import java.lang.reflect.Field;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

import org.redisson.api.RMapCache;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.haiyou.common.constants.sdk.TokenAccessEnum;
import com.haiyou.common.constants.token.ApiConstants;
import com.haiyou.common.jdbc.DbType;
import com.haiyou.common.util.date.DateUtilsV2;
import com.haiyou.common.util.string.StringUtils;
import com.haiyou.common.util.string.StringUtilsV2;
import com.haiyou.data.common.accessor.redis.redisson.mapping.RedissonMapCacheWrapper;
import com.haiyou.data.common.cache.redis.redisson.RedisRedisson;

import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;

/**
 * 
 * 玩家token 业务层
 * @author xingyuan
 * @Date 2023年6月19日 上午10:19:28
 */
@Slf4j
@Component
public class AccountTokenService {
	
	/**
	 * 令牌有效时长
	 */
	private static final int LIFE_MIN =  7 * 24 * 60;
	

	/**
	 * uid与时间redis存储分隔符
	 */
	public static final String UID_TIME_SPLIT = "::";
	
	/**
	 * key apiId
	 */
	private static Map<Integer, ApiToken> tokenMaps = Maps.newConcurrentMap();
	
	private RMapCache<String,AdminToken> adminMap;

	private static final String TOKEN_KEY_TOKEN_ACCOUNT = "k-a:";
	private static final String TOKEN_KEY_ACCOUNT_TOKEN = "a-k:";
	private static final String TOKEN_KEY_SUFFIX = ":token_map";
	private static final String TOKEN_TEMP_KEY_SUFFIX = ":token_map_temp";
	private static final String TOKEN_KEY_SUFFIX_ADMIN = ":token_map_admin";

	/**
	 * 创建token 对象
	 * 
	 * @param apiId
	 * @return
	 */
	private ApiToken createApiToken(int apiId) {
		RedissonClient redissionClient = RedisRedisson.getRedissonClient(DbType.SDK);
		RMapCache<String, AccountBean> ka = new RedissonMapCacheWrapper<>(redissionClient, String.class,
				TOKEN_KEY_TOKEN_ACCOUNT + apiId + TOKEN_KEY_SUFFIX);
		RMapCache<String, TokenBean> ak = new RedissonMapCacheWrapper<>(redissionClient, String.class,
				TOKEN_KEY_ACCOUNT_TOKEN + apiId + TOKEN_KEY_SUFFIX);

		RMapCache<String, Map<String, TokenBean>> akTemp = new RedissonMapCacheWrapper<>(redissionClient, String.class,
				TOKEN_KEY_ACCOUNT_TOKEN + apiId + TOKEN_TEMP_KEY_SUFFIX);

		return ApiToken.builder().ak_tokenMap(ak).ka_tokenMap(ka).ak_tokenTempMap(akTemp).apiId(apiId).build();
	}

	/**
	 * 初始化
	 */
	@PostConstruct
	public void init() {

		try {

			ApiConstants object = new ApiConstants();

			Class<ApiConstants> classz = ApiConstants.class;

			Field[] fields = classz.getFields();

			for (int i = 0; i < fields.length; i++) {

				int apiId = fields[i].getInt(object);

				tokenMaps.put(apiId, createApiToken(apiId));
			}

			createAdminToken();
			
		} catch (Exception e) {
			log.error(e.getMessage(), e);
			System.exit(0);
		}
	}
 

	private void createAdminToken() {
		RedissonClient redissionClient = RedisRedisson.getRedissonClient(DbType.SDK);
		adminMap = redissionClient.getMapCache(TOKEN_KEY_ACCOUNT_TOKEN + TOKEN_KEY_SUFFIX_ADMIN);
	}

	/**
	 * 游戏通过uid 获取token
	 * 
	 * @param uid
	 * @return
	 */
	public String getGameTokenById(String id) {
		return getTokenById(id, ApiConstants.game);
	}

	/**
	 * 游戏通过token 获取uid
	 * 
	 * @param token
	 * @return
	 */
	public String getGameIdByToken(String token) {
		return getIdByToken(token, ApiConstants.game);
	}

	/**
	 * 通过uid 获取token
	 * 
	 * @return
	 */
	public String getTokenById(String id, int apiId) {
		ApiToken apiToken = tokenMaps.get(apiId);
		TokenBean bean = apiToken.getAk_tokenMap().get(id);
		if (bean == null) {
			return null;
		}
		return bean.getToken();
	}
	
	/**
	 * 通过uid 获取超登token
	 * 
	 * @return
	 */
	public AdminToken getAdminTokenById(String id) {
		return adminMap.get(id);
	}

	
	public Collection<AdminToken> getAdminAll() {
		return adminMap.readAllValues();
	}
	
	
	
	public Collection<TokenBean> getTokenAll(String accountId, int apiId) {
		Map<String, TokenBean> map = tokenMaps.get(apiId).getAk_tokenTempMap().get(accountId);
		if (map != null) {
			return map.values();
		}
		return Lists.newArrayList();
	}
	
	/**
	 * 通过 token 获取uid
	 * 
	 * @param token
	 * @param apiId
	 * @return
	 */
	public String getIdByToken(String token, int apiId) {
		String result = getValueByToken(token, apiId);
		if (StringUtils.isEmpty(result)) {
			return result;
		}
		return result.split(UID_TIME_SPLIT)[0];
	}
	
	/**
	 * 通过token 获取映射id
	 * @param token
	 * @param tokenAccessEnum
	 * @return
	 */
	public String getIdByToken(String token,TokenAccessEnum tokenAccessEnum) {
		
		//可能是那些token
		Set<Integer> apiIds =  tokenAccessEnum.getApiIds();
		
		for (Integer apiId : apiIds) {
			String id = this.getIdByToken(token, apiId);
			if(!StringUtils.isEmpty(id)) {
				return id;
			}
		}
		
		return "";
	}
	
	/**
	 * 通过 token 获取uid
	 * 
	 * @param token
	 * @param apiId
	 * @return
	 */
	public String getValueByToken(String token, int apiId) {

		if (StringUtils.isEmpty(token)) {
			return null;
		}

		ApiToken apiToken = tokenMaps.get(apiId);

		if (ObjectUtils.isEmpty(apiToken)) {
			return null;
		}
		AccountBean bean = apiToken.getKa_tokenMap().get(token);
		if (bean == null) {
			return null;
		}
		return bean.getAccount();
	}

	/**
	 * 生成 对应uid token
	 * 
	 * @param uid
	 * @return
	 */
	public String buildToken(String uid, int apiId) {

		String token = createToken();

		return bindToken(uid, apiId, token);
	}
	
	/**
	 * 绑定 对应uid token
	 * 
	 * @param uid
	 * @return
	 */
	public String bindToken(String uid, int apiId,String  token) {
		
		ApiToken apiToken = tokenMaps.get(apiId);
		
		if (ObjectUtils.isEmpty(apiToken)) {
			throw new RuntimeException("参数错误,没有对应apiId:" + apiId);
		}
		long now = System.currentTimeMillis();
		
		// 需要删除的旧token
		TokenBean oldToken = apiToken.getAk_tokenMap().get(uid);
		
		TokenBean bean = new TokenBean(token, now);
		apiToken.getAk_tokenMap().fastPut(uid, bean, LIFE_MIN, TimeUnit.MINUTES);

		AccountBean a = new AccountBean(uid, now);
		apiToken.getKa_tokenMap().fastPut(token, a, LIFE_MIN, TimeUnit.MINUTES);

		// 更新token列表
		apiToken.getAk_tokenTempMap().compute(uid, (k, v) -> {
			if (v == null) {
				v = new HashMap<String, TokenBean>();
			}
			// 删除旧token
			if (oldToken != null) {
				v.remove(oldToken.getToken());
			}
			Iterator<Entry<String, TokenBean>> itr = v.entrySet().iterator();
			while (itr.hasNext()) {
				if (itr.next().getValue().getTime() + LIFE_MIN * DateUtilsV2.MINUTE_MILLISECOND <= now) {
					itr.remove();
				}
			}

			v.put(token, bean);
			return v;
		});
		// 设置过期时间
		apiToken.getAk_tokenTempMap().updateEntryExpirationAsync(uid, LIFE_MIN, TimeUnit.MINUTES, 0, TimeUnit.MINUTES);
		return token;
	}
	
	/**
	 * 生成 对应uid token
	 * 
	 * @param uid
	 * @return
	 */
	public String buildAdminToken(String uid,long minute,String tk) {

		AdminToken token = new AdminToken();

		token.setUid(uid);

		if (StringUtilsV2.isBlank(tk)) {
			tk = createToken();
		}
		token.setToken(tk);

		token.setExpireTime(System.currentTimeMillis() + minute * DateUtilsV2.MINUTE_MILLISECOND);

		adminMap.fastPut(uid, token, minute, TimeUnit.MINUTES);

		return token.getToken();
	}
	
	public void delAdminToken(String uid) {
		adminMap.remove(uid);
	}

	/**
	 * 创建生成token
	 * 
	 * @return
	 */
	public String createToken() {
		String uuid = UUID.randomUUID().toString();
		return uuid = uuid.replace("-", "");
	}
	
	
}
